LeetCode API Design Decisions
Understand the workflow and design considerations for the LeetCode API service.
Introduction#
The LeetCode service involves many components that play a vital role in providing all the functionalities to the users. We will start by analyzing the high-level structure of the LeetCode service. It consists of multiple subservices; we will discuss each service's workflow and inner functionality in this lesson. The appropriate architectural styles, data formats, and protocols are debated later in this lesson.
Design overview#
The design of the LeetCode API consists of five major services, as shown in the illustration below. As we can see, each service has a significant role and, therefore, accepts users’ requests directly, because it’s available as an endpoint to its users. Even if each service is elaborated on in detail along with its components, we’ll see how these services are interdependent and coupled to respond to user queries. Below, we explain the role of each service and the workflow to complete various functional requirements.
Requests from clients can ask the LeetCode service to perform operations such as listing coding problems, registering a coding contest, submitting a code, commenting on a topic, and so on. Each subservice is a complete service; we’ll discuss their workflows by analyzing the components involved in each service.
The working of each of the components of the LeetCode service is given below:
Components and Services Details
Component or Service | Details |
User Service |
|
Problem Service |
|
Contest Service |
|
Interview Service |
|
Discuss Service |
|
Cache |
|
Workflow#
In the following section, we will discuss different workflows in terms of the functional requirements we set for our LeetCode design problem. We’ve divided the workflow in terms of use cases and services.
User service#
In addition to handling the registration and login requests of the users, the user service is also responsible for coordination with other services. The user service enables end users to authenticate and authorize themselves to use services. As such, registered and logged-in users can solve issues in problem or contest services. The workflow of the user service is shown below:
Problems service #
The problems service tackles the requests received from the API gateway related to practice problems. The user can fetch a list and practice either of the problems in the list. The user can execute the code to evaluate its correctness. The problem service communicates with the code execution service, which executes the code using containers.
Note: Containerization is a type of virtualization that packages an application and its corresponding dependencies in a standard environment to streamline the development process. Instead of a complete hardware machine virtualization, containers are lightweight and portable.
The clients then get a response with the evaluation results provided by the code execution service. Moreover, the results are saved in the problem service to keep a record of the user's evaluation. The workflow is shown in the following illustration:
Contest service#
The contest service handles the user's requests related to contests. The requests can include registration for a contest, submitting the codes for the contest, viewing performance history, retrieving a contest's leaderboard, and so on. When a user submits codes while attempting a contest, the contest service submits codes to the pub-sub service. The pub-sub service further communicates with different connected services, such as code execution, plagiarism (a service that checks the originality of the code by using various tools), and so on, for further processing. The overall evaluation results are saved in the metadata service, which communicates the data to the user service, because users generally want to know the results of the contests they participated in. The following illustration shows the workflow of the contest service:
Point to Ponder
Question
Why can’t you replace the pub-sub service in the illustration above with an API gateway?
While hosting a contest, the contest service will have to admit a large number of distinct requests from thousands of participants. Furthermore, it will be necessary to coordinate between services in an asynchronous manner.
The pub-sub service is a natural fit for such scenarios as it decouples services, enables asynchronous communication, notifies services (repeatedly if needed), and queues a large number of related tasks for further processing. Finally, the pub-sub service notifies the participants when results are available.
API gateways cannot provide the services above, though they are known for disseminating requests and forwarding them to the relevant services.
Interview service#
The interview service allows users to conduct interviews with candidates. This service combines with Zoom to allow an interviewer to schedule an interview. When a request reaches the interview service to schedule an interview, the pub-sub service will notify Zoom and code-execution services to ensure the availability of resources to provide a seamless experience to the interviewer and candidate. During the interview, any coding problems submitted to the interview service are forwarded to the code-execution service via pub-sub. The code-execution service lets the pub-sub service notify the interviewer and candidate about the evaluation results. The following illustration shows the workflow of the interview service:
Note: Depending on the role of the user (interviewer or candidate), the interview service may show different levels of detail from the code-execution service. For instance, compile or run-time bugs could be reported to the candidate, whereas a detailed report (number of attempts to solve a problem, resource utilization, and so on) could be shared with the interviewer.
Discuss service#
The discuss service combines the comment and pub-sub services to enable users to discuss general queries and communicate with each other. Using the pub-sub service, users can create various topics, such as interview questions, experience, compensation, and job opportunities. The users can comment on any of the created topics and get notified about others' comments via the pub-sub service, as illustrated below:
Design considerations#
We’ve now comprehensively discussed the workflows of the different services in our LeetCode API design. Let’s move on to the design decisions on architecture, format, and communication protocols for the LeetCode service.
Architectural styles#
The architectural style in the LeetCode service is explained in two gradual steps, as shown below:
Client to API gateway: The client and API gateway communication is simple and follows a request-response model. REST is suitable, due to its simple and standardized way of managing resources.
API gateway to backend services: As we know from our previous analysis of the workflow of the LeetCode service, it comprises multiple and interdependent subservices. It must fetch data from multiple endpoints and consolidate them into a single response. GraphQL enables users to achieve consolidated responses by executing queries to fetch only the required data from multiple resources. The use of REST here is possible, but not ideal, because REST needs multiple requests to fulfill most of the user requests that can be handled in a single request using GraphQL. Therefore, it’s preferable to use GraphQL instead of REST.
Note: Small devices with limited processing power and battery life, such as cell phones, smartwatches, and Internet of Things (IoT) devices, can benefit from the usage of GraphQL. This is because GraphQL avoids the need to place subsequent requests to obtain a set of data from multiple services.
Communication protocols#
The HTTP version can be better selected by analyzing data in the request and response of the service. Firstly, the data doesn't contain any media files to be transferred, so no multiplexing is required. Secondly, our focus is on fast and reliable data transfers between client and backend services. HTTP/1.1 is a suitable option due to the availability of its support and convenient implementation. We could achieve the same features using HTTP/2.0, but it incurs the extra complexity of header compression and multiplexing, which is not required in our operations.
Since the LeetCode service sends various notifications to the clients, we need an event-driven protocol to transmit notifications to the users. And since users may not maintain a persistent connection with the service, we can consider employing the WebSub protocol.
Data formats#
Our requirements fit well with JSON because of the type of data we exchange with the server and the suitability of JSON with GraphQL architecture. Moreover, JSON's readability and compactness make it the perfect choice for communication between clients and services.
Summary#
We discussed the reasons behind the design considerations affecting the LeetCode API design. The following table summarizes our design decisions:
Design Considerations | Client to API Gateway | API Gateway to Backend Services | Backend to Subscribers |
Architecture style | REST | GraphQL | Event-driven |
Data format | JSON | JSON | JSON |
Protocol/ HTTP version | HTTP/1.1 | HTTP/1.1 | WebSub |
Requirements of the LeetCode API
API Model for LeetCode Service